package com.jtw.conf.shiro;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;

/**
 * DESCRIPT:自定义的角色、权限校验过滤器。
 * @author cjsky666
 * @date 2018/9/3 10:08
 */
@Slf4j
public class CustomAuthorizationFilter extends AuthorizationFilter {
    /**
     * 权限过滤器的key
     */
    public static final String CSRF_TOKEN_KEY = "CSRFToken";
    public static final String FilterKey = "custom_roles";
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        log.info("私有接口--权限校验--preHandle");
        return super.preHandle(request, response);
    }

    @Override
    public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
        log.info("私有接口--权限校验--afterCompletion");
        super.afterCompletion(request, response, exception);
    }
    /**
     * 权限校验处理
     * @param servletRequest
     * @param servletResponse
     * @param o
     * @return
     * @throws Exception
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
        log.info("私有接口--权限校验---isAccessAllowed");
        Subject subject = getSubject(servletRequest, servletResponse);
        //TODO 此处可以添加特定账户为全权管理账户。不校验 直接return true
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;

        String CSRFToken = httpServletRequest.getHeader(CSRF_TOKEN_KEY);
        if(StringUtils.isEmpty(CSRFToken)||httpServletRequest.getSession().getAttribute(CSRF_TOKEN_KEY)==null){
            return false;
        }

        if(!CSRFToken.equals(httpServletRequest.getSession().getAttribute(CSRF_TOKEN_KEY).toString())){
            return false;
        }
        String[] rolesArray = (String[]) o;
        if (rolesArray == null || rolesArray.length == 0) {
            return true;
        }

        for (String aRolesArray : rolesArray) {
            String[] filterArray = aRolesArray.split(":");
            if (filterArray == null || filterArray.length < 2) {
//                如果有多个角色的时候
//                刚好前面的的角色的权限为空
//                使用return  false 则会打断循环。
//                出现权限误判，因为第二个角色可能会拥有该权限
//                return false;
                continue;
            }

            String method = httpServletRequest.getMethod();

            if (method.equals(filterArray[0])) {
                String[] roles = filterArray[1].split("\\|");
                for (String role : roles) {
                    if (subject.hasRole(role)) {
                        return true;
                    }
                }
                return false;
            } else {
                continue;
            }
        }
        return false;
    }


    /**
     * 权限校验不通过处理
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        log.info("私有接口--权限校验---onAccessDenied");
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;

        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        httpServletResponse.setStatus(HttpStatus.OK.value());
        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        PrintWriter out = httpServletResponse.getWriter();
        Subject subject = this.getSubject(request, response);

        String CSRFToken = httpServletRequest.getHeader(CSRF_TOKEN_KEY);
        log.info("header中的CSRFToken是"+CSRFToken);
        log.info("session中的CSRFToken是"+subject.getSession().getAttribute(CSRF_TOKEN_KEY));

        if (subject.getPrincipal() == null) {
            this.saveRequest(request);//保存触发登录之前的访问路径
            out.print("{\"code\":"+1002+",\"message\":\"登录状态丢失\",\"data\":"+null+",\"serviceTime\":"+Calendar.getInstance().getTimeInMillis()+"}");
        }else if(StringUtils.isEmpty(CSRFToken)||subject.getSession().getAttribute(CSRF_TOKEN_KEY)==null){
            out.print("{\"code\":"+1002+",\"message\":\"令牌失效\",\"data\":"+null+",\"serviceTime\":"+Calendar.getInstance().getTimeInMillis()+"}");
        }else if(!CSRFToken.equals(subject.getSession().getAttribute(CSRF_TOKEN_KEY).toString())){
            out.print("{\"code\":"+1001+",\"message\":\"令牌无效\",\"data\":"+null+",\"serviceTime\":"+Calendar.getInstance().getTimeInMillis()+"}");
        }else{
            out.print("{\"code\":"+10001+",\"message\":\"权限不足,访问失败\",\"data\":"+null+",\"serviceTime\":"+Calendar.getInstance().getTimeInMillis()+"}");
        }
        out.flush();
        out.close();
        return false;
    }
}
